#!/usr/bin/python

# Copyright (c) 2009, Purdue University
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
# 
# Neither the name of the Purdue University nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Regression test for dnstreeexport

Make sure you are running this against a database that can be destroyed.

DO NOT EVER RUN THIS TEST AGAINST A PRODUCTION DATABASE.
"""

__copyright__ = 'Copyright (C) 2009, Purdue University'
__license__ = 'BSD'
__version__ = '0.18'

import tarfile
import unittest
import os
import getpass

import tree_exporter_test_lib  

class TestDnsTreeExport(tree_exporter_test_lib.TreeExportTestCase):
  def testMakeFilesFromDB(self):
    output = os.popen('python %s -c %s' % (
        tree_exporter_test_lib.EXEC, tree_exporter_test_lib.CONFIG_FILE))
    output.read()
    output.close()
    for fname in os.listdir(self.backup_dir):
      if( not fname.endswith('.tar.bz2') ):
        continue
      if( 'dns_tree' in fname ):
        tar = tarfile.open('%s/%s' % (self.backup_dir, fname))
        tar.extractall(path='./%s' % self.root_config_dir)
        tar.close()
        break
    else:
      raise Exception("File not found")
    ##Test Files
    handle = open(
        './%s/ns1.university.edu/ns1.university.edu.info' %
        self.root_config_dir, 'r')
    lines = handle.read()
    handle.close()
    self.assertEqual(lines,
        '[server_info]\n'
        'test_dir = %s\n'
        'bind_version = undetermined\n'
        'server_name = ns1.university.edu\n'
        'server_user = %s\n'
        'bind_dir = %s\n'
        '\n'
        '[tools]\n'
        'tar = True\n'
        '\n' % (tree_exporter_test_lib.TESTDIR, getpass.getuser(), tree_exporter_test_lib.BINDDIR))

    handle = open('./%s/ns1.university.edu/named.conf.a' %
        self.root_config_dir, 'r')
    output = handle.read()
    handle.close()
    self.assertEqual(output,
        '#This named.conf file is autogenerated. DO NOT EDIT\n'
        'include "/etc/rndc.key";\n'
        'logging { category "update-security" { "security"; };\n'
        'category "queries" { "query_logging"; };\n'
        'channel "query_logging" { syslog local5;\n'
        'severity info; };\n'
        'category "client" { "null"; };\n'
        'channel "security" { file "/var/log/named-security.log" versions 10 size 10m;\n'
        'print-time yes; }; };\n'
        'options { directory "%s";\n'
        'recursion no;\n'
        'max-cache-size 512M; };\n'
        'controls { inet * allow { control-hosts; } keys { rndc-key; }; };\n'
        'acl secret {\n'
        '\t10.10/32;\n'
        '};\n'
        '\n'
        'acl public {\n'
        '\t192.168.1.4/30;\n'
        '\t10.10/32;\n'
        '};\n'
        '\n'
        'view "external" {\n'
        '\tmatch-clients { \n'
        '\t\t\n'
        '\t };\n'
        '\trecursion no;\n'
        '\tzone "." {\n'
        '\t\ttype hint;\n'
        '\t\tfile "named.ca";\n'
        '\t};\n'
        '\tzone "university.edu" {\n'
        '\t\ttype master;\n'
        '\t\tfile "external/university.edu.db";\n'
        '\t\tallow-update { none; };\n'
        '\t};\n'
        '\tzone "4.3.2.in-addr.arpa" {\n'
        '\t\ttype master;\n'
        '\t\tfile "external/4.3.2.in-addr.db";\n'
        '\t\tallow-update { none; };\n'
        '\t};\n'
        '};' % tree_exporter_test_lib.NAMED_DIR)

    handle = open(
        './%s/ns1.university.edu/named/external/4.3.2.in-addr.db' %
        self.root_config_dir, 'r')
    output = handle.read()
    handle.close()
    self.assertEqual(output,
                     '; This zone file is autogenerated. DO NOT EDIT.\n'
                     '$ORIGIN 4.3.2.in-addr.arpa.\n'
                     '@ 3600 in soa ns1.university.edu. '
                     'admin@university.edu. 20091226 5 5 5 5\n'
                     '1 3600 in ptr computer1.university.edu.\n')

    handle = open(
        './%s/ns1.university.edu/named/external/university.edu.db' %
        self.root_config_dir, 'r')
    output = handle.read()
    handle.close()
    self.assertEqual(output,
        '; This zone file is autogenerated. DO NOT EDIT.\n'
        '$ORIGIN university.edu.\n'
        '@ 3600 in soa ns1.university.edu. '
        'admin@university.edu. 20091234 5 5 5 5\n'
        '@ 3600 in ns ns1.university.edu.\n'
        '@ 3600 in ns ns2.university.edu.\n'
        '@ 3600 in mx 1 mail1.university.edu.\n'
        '@ 3600 in mx 1 mail2.university.edu.\n'
        'computer1 3600 in a 1.2.3.5\n'
        'computer3 3600 in a 1.2.3.6\n')

    handle = open(
        './%s/ns1.int.university.edu/ns1.int.university.edu.info' %
        self.root_config_dir, 'r')
    self.assertEqual(handle.read(),
        '[server_info]\n'
        'test_dir = %s\n'
        'bind_version = undetermined\n'
        'server_name = ns1.int.university.edu\n'
        'server_user = %s\n'
        'bind_dir = %s\n'
        '\n'
        '[tools]\n'
        'tar = True\n'
        '\n' % (tree_exporter_test_lib.TESTDIR, getpass.getuser(), tree_exporter_test_lib.BINDDIR))
    handle.close()

    handle = open('./%s/ns1.int.university.edu/named.conf.a' %
                  self.root_config_dir, 'r')    
    output = handle.read()
    handle.close()
    self.assertEqual(output,
		    '#This named.conf file is autogenerated. DO NOT EDIT\n'
        'include "/etc/rndc.key";\n'
        'logging { category "update-security" { "security"; };\n'
        'category "queries" { "query_logging"; };\n'
        'channel "query_logging" { syslog local5;\n'
        'severity info; };\n'
        'category "client" { "null"; };\n'
        'channel "security" { file "/var/log/named-security.log" versions 10 size 10m;\n'
        'print-time yes; }; };\n'
        'options { directory "%s";\n'
        'recursion no;\n'
        'max-cache-size 512M; };\n'
        'controls { inet * allow { control-hosts; } keys { rndc-key; }; };\n'
        'acl secret {\n'
        '\t10.10/32;\n'
        '};\n'
        '\n'
        'acl public {\n'
        '\t192.168.1.4/30;\n'
        '\t10.10/32;\n'
        '};\n'
        '\n'
        'view "external" {\n'
        '\tmatch-clients { \n'
        '\t\tpublic;\n'
        '\t };\n'
        '\trecursion no;\n'
        '\tzone "." {\n'
        '\t\ttype hint;\n'
        '\t\tfile "named.ca";\n'
        '\t};\n'
        '\tzone "university.edu" {\n'
        '\t\ttype master;\n'
        '\t\tfile "external/university.edu.db";\n'
        '\t\tallow-update { none; };\n'
        '\t};\n'
        '\tzone "4.3.2.in-addr.arpa" {\n'
        '\t\ttype master;\n'
        '\t\tfile "external/4.3.2.in-addr.db";\n'
        '\t\tallow-update { none; };\n'
        '\t};\n'
        '};\n'
        'view "internal" {\n'
        '\tmatch-clients { \n'
        '\t\t!public;\n'
        '\t\tsecret;\n'
        '\t };\n'
        '\trecursion no;\n'
        '\tzone "." {\n'
        '\t\ttype hint;\n'
        '\t\tfile "named.ca";\n'
        '\t};\n'
        '\tzone "university.edu" {\n'
        '\t\ttype master;\n'
        '\t\tfile "internal/university.edu.db";\n'
        '\t\tallow-update { none; };\n'
        '\t};\n'
        '\tzone "168.192.in-addr.arpa" {\n'
        '\t\ttype master;\n'
        '\t\tfile "internal/168.192.in-addr.db";\n'
        '\t\tallow-update { none; };\n'
        '\t};\n'
        '};' % tree_exporter_test_lib.NAMED_DIR)

    handle = open(
        './%s/ns1.int.university.edu/named/external/4.3.2.in-addr.db' % 
        self.root_config_dir, 'r')
    output = handle.read()
    handle.close()
    self.assertEqual(output,
        '; This zone file is autogenerated. DO NOT EDIT.\n'
        '$ORIGIN 4.3.2.in-addr.arpa.\n'
        '@ 3600 in soa ns1.university.edu. '
        'admin@university.edu. 20091226 5 5 5 5\n'
        '1 3600 in ptr computer1.university.edu.\n')

    handle = open(
        './%s/ns1.int.university.edu/named/external/university.edu.db' %
        self.root_config_dir, 'r')
    output = handle.read()
    handle.close()
    self.assertEqual(output,
        '; This zone file is autogenerated. DO NOT EDIT.\n'
        '$ORIGIN university.edu.\n'
        '@ 3600 in soa ns1.university.edu. '
        'admin@university.edu. 20091234 5 5 5 5\n'
        '@ 3600 in ns ns1.university.edu.\n'
        '@ 3600 in ns ns2.university.edu.\n'
        '@ 3600 in mx 1 mail1.university.edu.\n'
        '@ 3600 in mx 1 mail2.university.edu.\n'
        'computer1 3600 in a 1.2.3.5\n'
        'computer3 3600 in a 1.2.3.6\n')

    handle = open(
        './%s/ns1.int.university.edu/named/internal/168.192.in-addr.db' %
        self.root_config_dir, 'r')
    output = handle.read()
    handle.close()
    self.assertEqual(output,
        '; This zone file is autogenerated. DO NOT EDIT.\n'
        '$ORIGIN 168.192.in-addr.arpa.\n'
        '@ 3600 in soa ns1.university.edu. '
        'admin@university.edu. 20091225 5 5 5 5\n'
        '4 3600 in ptr computer4.university.edu.\n')

    handle = open(
        './%s/ns1.int.university.edu/named/internal/university.edu.db' %
        self.root_config_dir, 'r')
    output = handle.read()
    handle.close()
    self.assertEqual(output,
        '; This zone file is autogenerated. DO NOT EDIT.\n'
        '$ORIGIN university.edu.\n'
        '@ 3600 in soa ns1.university.edu. '
        'admin@university.edu. 20091229 5 5 5 5\n'
        '@ 3600 in ns ns1.university.edu.\n'
        '@ 3600 in ns ns2.university.edu.\n'
        '@ 3600 in mx 1 mail1.university.edu.\n'
        '@ 3600 in mx 1 mail2.university.edu.\n'
        'computer1 3600 in a 192.168.1.1\n'
        'computer2 3600 in a 192.168.1.2\n'
        'computer4 3600 in a 192.168.1.4\n')

    handle = open(
        './%s/dns4.university.edu/dns4.university.edu.info' %
        self.root_config_dir, 'r')
    self.assertEqual(handle.read(),
        '[server_info]\n'
        'test_dir = %s\n'
        'bind_version = undetermined\n'
        'server_name = dns4.university.edu\n'
        'server_user = %s\n'
        'bind_dir = %s\n'
        '\n'
        '[tools]\n'
        'tar = True\n'
        '\n' % (tree_exporter_test_lib.TESTDIR, getpass.getuser(), tree_exporter_test_lib.BINDDIR))
    handle.close()
    handle = open('./%s/dns4.university.edu/named.conf.a' % 
                  self.root_config_dir, 'r')
    self.assertEqual(
        handle.read(), '#This named.conf file is autogenerated. DO NOT EDIT\n'
            'include "/etc/rndc.key";\n'
            'logging { category "update-security" { "security"; };\n'
            'category "queries" { "query_logging"; };\n'
            'channel "query_logging" { syslog local5;\n'
            'severity info; };\n'
            'category "client" { "null"; };\n'
            'channel "security" { file "/var/log/named-security.log" versions 10 size 10m;\n'
            'print-time yes; }; };\n'
            'options { directory "%s";\n'
            'recursion no;\n'
            'max-cache-size 512M; };\n'
            'controls { inet * allow { control-hosts; } keys { rndc-key; }; };\n'
            'acl secret {\n'
            '\t10.10/32;\n'
            '};\n'
            '\n'
            'acl public {\n'
            '\t192.168.1.4/30;\n'
            '\t10.10/32;\n'
            '};\n'
            '\n'
            'view "private" {\n'
            '\tmatch-clients { \n'
            '\t\t!secret;\n'
            '\t };\n'
            '\trecursion no;\n'
            '\tzone "." {\n'
            '\t\ttype hint;\n'
            '\t\tfile "named.ca";\n'
            '\t};\n'
            '\tzone "university.edu" {\n'
            '\t\ttype master;\n'
            '\t\tfile "private/university.edu.db";\n'
            '\t\tallow-update { none; };\n'
            '\t};\n'
            '};' % tree_exporter_test_lib.NAMED_DIR)
    handle.close()
    handle = open(
        './%s/dns4.university.edu/named/private/university.edu.db' %
        self.root_config_dir, 'r')
    output = handle.read()
    self.assertEqual(output,
        '; This zone file is autogenerated. DO NOT EDIT.\n'
        '$ORIGIN university.edu.\n'
        '@ 3600 in soa ns1.university.edu. '
        'admin@university.edu. 20091227 5 5 5 5\n'
        '@ 3600 in ns ns1.university.edu.\n'
        '@ 3600 in ns ns2.university.edu.\n'
        '@ 3600 in mx 1 mail1.university.edu.\n'
        '@ 3600 in mx 1 mail2.university.edu.\n')
    handle.close()

    output = os.popen('python %s -c %s' % (
        tree_exporter_test_lib.EXEC, tree_exporter_test_lib.CONFIG_FILE))
    output_string = output.read()
    output.close()
    self.assertEquals(output_string, 'No changes made to database. In order '
                                     'to export use the --force flag.\n')
    output = os.popen('python %s -c %s --force' % (
        tree_exporter_test_lib.EXEC, tree_exporter_test_lib.CONFIG_FILE))
    output_string = output.read()
    output.close()
    self.assertEquals(output_string, '')

  for fname in os.listdir('.'):
    if( fname.endswith('.bz2') ):
      os.remove(fname)

  def testErrors(self):
    zones_dict = {}

    try:
      self.db_instance.StartTransaction()
      zones_dict['zone_name'] = u'university.edu'
      self.db_instance.RemoveRow('zones', zones_dict)
    finally:
      self.db_instance.EndTransaction()
    output = os.popen('python %s -c %s -f' % (
        tree_exporter_test_lib.EXEC, tree_exporter_test_lib.CONFIG_FILE))
    output_string = output.read()
    output.close()
    self.assertEquals(output_string,
        'ERROR: Server set private_dns has no zones in private view.\n')

    views_dict = {}
    try:
      self.db_instance.StartTransaction()

      views_dict['view_name'] = u'internal'
      self.db_instance.RemoveRow('views', views_dict)

      views_dict['view_name'] = u'external'
      self.db_instance.RemoveRow('views', views_dict)

      views_dict['view_name'] = u'private'
      self.db_instance.RemoveRow('views', views_dict)
    finally:
      self.db_instance.EndTransaction()

    output = os.popen('python %s -c %s' % (
        tree_exporter_test_lib.EXEC, tree_exporter_test_lib.CONFIG_FILE))
    output_string = output.read()
    output.close()
    self.assertEquals(output_string,
        'ERROR: Server set external_dns has no views.\n')


    dns_server_sets_dict = {}
    try:
      self.db_instance.StartTransaction()
      dns_server_sets_dict['dns_server_set_name'] = u'internal_dns'
      self.db_instance.RemoveRow('dns_server_sets', dns_server_sets_dict)

      dns_server_sets_dict['dns_server_set_name'] = u'external_dns'
      self.db_instance.RemoveRow('dns_server_sets', dns_server_sets_dict)

      dns_server_sets_dict['dns_server_set_name'] = u'private_dns'
      self.db_instance.RemoveRow('dns_server_sets', dns_server_sets_dict)
    finally:
      self.db_instance.EndTransaction()

    output = os.popen('python %s -c %s' % (
        tree_exporter_test_lib.EXEC, tree_exporter_test_lib.CONFIG_FILE))
    output_string = output.read()
    output.close()
    self.assertEquals(output_string, 'ERROR: No dns server sets found.\n')

  for fname in os.listdir('.'):
    if( fname.endswith('.bz2') ):
      os.remove(fname)

if( __name__ == '__main__' ):
      unittest.main()
